package com.xiangban.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xiangban.dao.*;
import com.xiangban.exception.BizException;
import com.xiangban.feign.DoctorFeign;
import com.xiangban.feign.MessageFeign;
import com.xiangban.model.*;
import com.xiangban.model.dto.AccompanyReceiveOrderDto;
import com.xiangban.model.dto.AccompanyReceiveStatusDto;
import com.xiangban.model.res.ApiResult;
import com.xiangban.model.res.ApiResultCode;
import com.xiangban.model.vo.OrderCommentVo;
import com.xiangban.model.vo.OrderVo;
import com.xiangban.rabbitMq.SendOrderAccompany;
import com.xiangban.service.OrderService;
import com.xiangban.utils.CommonUtils;
import com.xiangban.utils.DateUtil;
import com.xiangban.utils.PageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.xiangban.utils.CommonUtils.BizEmpty;
import static com.xiangban.utils.CommonUtils.getOrderNo;

/**
 * @Author Mr. MaYaYun
 * @Data 2021/12/8 14:32
 */
@Service
public class OrderServiceImpl implements OrderService {

    public static final Long DELAY_ACCOMPANY_TIME = 1000*60*60L;//陪诊接单时间
    public static String appointmentTime = " 11:00:00";//当天十一点过后就不能预约
    public static BigDecimal unitPrice = new BigDecimal(20.00);//超出距离单价


    @Autowired
    private CommonUtils commonUtils;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HospitalMapper hospitalMapper;
    @Autowired
    private SourceConfigMapper sourceConfigMapper;
    @Autowired
    private RelationMapper relationMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private SendOrderAccompany sendOrderAccompany;
    @Autowired
    private PageUtil pageUtil;
    @Autowired
    private AccompanyReceiveStatusMapper receiveStatusMapper;
    @Autowired
    private AccompanyReceiveOrderMapper receiveOrderMapper;
    @Autowired
    private AccompanyMapper accompanyMapper;
    @Autowired
    private OrderCommentMapper orderCommentMapper;
    @Autowired
    private DoctorFeign doctorFeign;
    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private OrderWasteMapper orderWasteMapper;
    @Autowired
    private AccompanyWalletMapper accompanyWalletMapper;
    @Autowired
    private AccompanyWalletRecodeMapper accompanyWalletRecodeMapper;
    @Autowired
    private MessageFeign messageFeign;
    @Value("${smsTemplate.UserSmsId}")
    private String smsTemplate;
    @Value("${smsTemplate.AccompanySmsId}")
    private String AccompanySmsId;


    @Override
    public Object estimateOrderMoney(Order order) {
        //基础金额
        Relation relation = new Relation();
        relation.setId(order.getPatientId());
        Relation relation1 = relationMapper.getRelation(relation);
        SourceConfig sourceConfig = new SourceConfig();
        sourceConfig.setId(relation1.getSource());
        sourceConfig.setType(order.getType());
        SourceConfig sourceConfigByIdAndType = sourceConfigMapper.getSourceConfigByIdAndType(sourceConfig);
        BigDecimal estimate = sourceConfigByIdAndType.getMoney();

        //超出金额
        BigDecimal overBudget  = new BigDecimal("0.00");
        //路程总距离 (m)
        Hospital hospitals = new Hospital();
        hospitals.setId(order.getHospitalDrugId());
        hospitals.setLatitude(order.getStartLatitude());
        hospitals.setLongitude(order.getStartLongitude());
        Integer sumDistance = hospitalMapper.calculateDistance(hospitals);
        //路程总公里
        BigDecimal distanceKm= new BigDecimal(sumDistance).divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP);
        //免费公里
        BigDecimal freeDistance = new BigDecimal(5.00);
        //超出免费距离
        if (distanceKm.compareTo(freeDistance) >0){
            if (sourceConfigByIdAndType.getRestrictions() == 1){//卫健委(不限制距离)
                overBudget = overBudget(distanceKm, freeDistance);
            }
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("estimate",estimate);
        map.put("overBudget",overBudget);
        return map;
    }

    @Override
    @Transactional
    public void createOrder(Order order) throws ParseException {

        //校验出行时间是否合理
        checkTime(order.getStartTime());

        //生成订单编号
        String orderNo = getOrderNo();

        //基础金额
        Relation relation = new Relation();
        relation.setId(order.getPatientId());
        Relation relation1 = relationMapper.getRelation(relation);
        SourceConfig sourceConfig = new SourceConfig();
        sourceConfig.setId(relation1.getSource());
        sourceConfig.setType(order.getType());
        SourceConfig sourceConfigByIdAndType = sourceConfigMapper.getSourceConfigByIdAndType(sourceConfig);
        BigDecimal estimate = sourceConfigByIdAndType.getMoney();

        //超出金额
        BigDecimal overBudget  = new BigDecimal("0.00");

        //路程总距离 (m)
        Hospital hospitals = new Hospital();
        hospitals.setId(order.getHospitalDrugId());
        hospitals.setLatitude(order.getStartLatitude());
        hospitals.setLongitude(order.getStartLongitude());
        Integer sumDistance = hospitalMapper.calculateDistance(hospitals);
        //路程总公里
        BigDecimal distanceKm= new BigDecimal(sumDistance).divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP);
        //免费公里
        BigDecimal freeDistance = new BigDecimal(5.00);
        //超出免费距离
        if (distanceKm.compareTo(freeDistance) >0){
            if (sourceConfigByIdAndType.getRestrictions() == 1){//卫健委(不限制距离)
                overBudget = overBudget(distanceKm, freeDistance);
            }
        }
        //实际价格  (基础金额 + 超出金额(根据不同来源 订单价格不同))
        BigDecimal money = estimate.add(overBudget);

        //陪诊费用
        BigDecimal accompanyMoney = sourceConfigByIdAndType.getAccompanyMoney();
        //获取陪诊加价部分
        if (!BizEmpty(order.getAccompanyId())) {
            UserAccompany accompanyUnitPrice = accompanyMapper.getAccompanyUnitPrice(order.getAccompanyId());
            accompanyMoney = accompanyMoney.add(accompanyUnitPrice.getUnitPrice());
        }

        //订单类型
        int payType = relation1.getSource();
        Relation relation2 = new Relation();
        relation2.setId(order.getPatientId());
        relation2.setUseNumber(relation1.getUseNumber()+1);
        order.setPayType(payType);//订单类型：1 微信支付 2 残联代付 3 卫健委 4 会员免费 5陪诊代付
        //判断用户免费次数（残联除外）
        if (payType != 2){
            if (relation1.getFreeNumber() <= 0){
                order.setPayType(5);//订单类型：1 微信支付 2 残联代付 3 卫健委 4 会员免费 5陪诊代付
                relation2.setFreeNumber(relation1.getFreeNumber());
            }else {
                relation2.setFreeNumber(relation1.getFreeNumber()-1);
            }
        }
        //#更改患者使用和免费次数
        relationMapper.updateUserFeeNumber(relation2);

        order.setOrderNo(orderNo);//订单号
        order.setEstimate(money);//预估金额
        order.setMoney(money);//实际金额
        order.setExceed(overBudget);//超出金额 5 公里 20 元
        order.setType(order.getType());//1 门诊 2 血透 3 配药
        order.setStatus(2);//订单状态
        order.setUserId(0);//下单用户id
        //陪诊人员id
        if (!BizEmpty(order.getAccompanyId())) {
            UserAccompany accompany = accompanyMapper.getAccompanyUnitPrice(order.getAccompanyId());
            //发送信息至陪诊员
            HashMap<String, Object> map = new HashMap<>();
            Send(accompany.getPhone(),AccompanySmsId,map);

            //#超时拒绝接单
            sendOrderAccompany.sendMessage(orderNo,DELAY_ACCOMPANY_TIME);
            order.setAccompanyStatus(0);
        }else {
            order.setAccompanyId(0);
            order.setAccompanyStatus(0);
        }
        order.setStartAddress(order.getStartAddress());//出发地址
        order.setStartLatitude(order.getStartLatitude());//出发纬度;
        order.setStartLongitude(order.getStartLongitude());//出发经度
        order.setStartTime(order.getStartTime());//出发时间
        order.setSource(1);//1 pc  2 移动端
        order.setVisit(0);//回访状态 0 未回访 1 已回访
        order.setIsDelete(0);//0 正常  非0 删除
        order.setInitiateId(Integer.parseInt(commonUtils.getShopId(request)));//发起人id  shop_login=>id
        order.setDistance(sumDistance);//路程距离
        order.setBasic(estimate);//基本费用
        order.setAccompanyMoney(accompanyMoney);
//        System.out.println(JSONObject.toJSONString(order));
        orderMapper.insertOrder(order);


//        saveOrderWaste(orderNo,commonUtils.getWasteNumber(),);

        //下单成功发送信息患者
        HashMap<String, Object> map = new HashMap<>();
        Send(relation1.getPhone(),smsTemplate,map);
    }

//    private void saveOrderWaste(){
//        OrderWaste orderWaste = new OrderWaste();
//            orderWasteMapper.insertOrderWaste(orderWaste);
//    }

    @Override
    public void finishOrder(Order order) {
        if (BizEmpty(order.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }

        order.setStatus(5);
        orderMapper.updateOrder(order);

        Order accompany = orderMapper.getAccompanyId(order.getOrderNo());

        //增加陪诊钱包金额
        AccompanyWallet accompanyWallet = new AccompanyWallet();
        accompanyWallet.setAccompanyId(accompany.getAccompanyId());
        accompanyWallet.setMoney(accompany.getAccompanyMoney());
        accompanyWalletMapper.updateAccompanyWallet(accompanyWallet);

        //增加陪诊钱包记录
        AccompanyWallet accompanyWallet1 = accompanyWalletMapper.getAccompanyWallet(accompany.getAccompanyId());
        AccompanyWalletRecode accompanyWalletRecode = new AccompanyWalletRecode();
        accompanyWalletRecode.setWalletId(accompanyWallet1.getId());
        accompanyWalletRecode.setTransactionNo(order.getOrderNo());
        accompanyWalletRecode.setStatus(0);
        accompanyWalletRecode.setMoney(accompany.getAccompanyMoney());
        accompanyWalletRecode.setType(1);
        accompanyWalletRecodeMapper.insertWalletByWalletId(accompanyWalletRecode);

    }

    @Override
    public void remarkOrVisit(Order order) {
        if (BizEmpty(order.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        orderMapper.updateOrderRemarkOrVisit(order);
    }

    @Override
    public PageInfo<OrderVo> listOrderPage(OrderVo orderVo) {
        String shopId = commonUtils.getShopId(request);
        Shop shop = new Shop();
        shop.setShopId(Integer.parseInt(shopId));
        Shop shopInformation = shopMapper.getShopInformation(shop);
        orderVo.setPayType(shopInformation.getShopType());
        PageHelper.startPage(pageUtil.getPage().getPageNum(),pageUtil.getPage().getPageSize());
        List<OrderVo> orderVoList = orderMapper.listOrder(orderVo);
        return new PageInfo<>(orderVoList);
    }

    @Override
    public Object getOrder(OrderVo orderVo) {
        if (BizEmpty(orderVo.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        return orderMapper.getOrder(orderVo);
    }

    @Override
    public Object listAccompanyReceiveStatus(AccompanyReceiveStatusDto receiveStatusDto) {
        if (BizEmpty(receiveStatusDto.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }

        List<AccompanyReceiveStatusDto> accompanyReceiveStatuses = receiveStatusMapper.listAccompanyReceiveStatus(receiveStatusDto);
        for (AccompanyReceiveStatusDto accompanyReceiveStatus : accompanyReceiveStatuses) {
            HashMap<String, Object> address = commonUtils.getAddress(accompanyReceiveStatus.getLongitude().toString(), accompanyReceiveStatus.getLatitude().toString());
            accompanyReceiveStatus.setAddress(address.get("formattedAddress").toString());
        }
        return accompanyReceiveStatuses;
    }

    @Override
    public Object getMedicalData(AccompanyReceiveOrder receiveOrder) {
        if (BizEmpty(receiveOrder.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        AccompanyReceiveOrderDto accompanyReceiveOrder = receiveOrderMapper.getAccompanyReceiveOrder(receiveOrder);
        if (accompanyReceiveOrder != null){
            if (!BizEmpty(accompanyReceiveOrder.getData())){
                JSONArray jsonArray = JSONArray.parseArray(accompanyReceiveOrder.getData());
                List<String> list = jsonArray.toJavaList(String.class);
                accompanyReceiveOrder.setMedicalData(list);
            }
        }
        return accompanyReceiveOrder;
    }

    @Override
    public Object getServiceRating(OrderComment orderComment) {
        if (BizEmpty(orderComment.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        OrderCommentVo orderComment1 = orderCommentMapper.getOrderComment(orderComment);
        if (orderComment1 != null){
            JSONArray jsonArray = JSONArray.parseArray(orderComment1.getImages());
            List<String> list = jsonArray.toJavaList(String.class);
            orderComment1.setCommentImages(list);
            orderComment1.setImages(null);
        }
        return orderComment1;
    }


    @Override
    public void cancelOrder(Order order) {
        if (BizEmpty(order.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }

        //获取订单信息
        Order orderByOrderNo = orderMapper.getOrderByOrderNo(order.getOrderNo());

        if (orderByOrderNo.getStatus() == 2){//预约中
            if (orderByOrderNo.getSource() == 2){//移动端

                //调用doctor接口退款
                HashMap<String, String> map = new HashMap<>();
                map.put("cause","后台取消订单");
                map.put("orderNo",order.getOrderNo());
                doctorFeign.refundOrderList(map);
            }
            Order order1 = new Order();
            order1.setStatus(6);//订单状态 1待支付 2 预约中 3进行中 4待评价 5已完成 6 已取消 7已超时
            order1.setOrderNo(order.getOrderNo());
            orderMapper.updateOrder(order1);

        }else {
            throw new BizException(ApiResultCode.CAN_NOT_CANCEL_ORDER);
        }
    }

    @Override
    public void telephoneInterviews(Order order) {
        if (BizEmpty(order.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        if (BizEmpty(order.getRecording())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }

        orderMapper.updateRecording(order);
    }

    @Override
    public void updateMedicalData(AccompanyReceiveOrder receiveOrder) {
        if (BizEmpty(receiveOrder.getOrderNo())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        if (BizEmpty(receiveOrder.getData())){
            throw new BizException(ApiResultCode.PARAMETER_DEFICIENCY);
        }
        receiveOrderMapper.updateAccompanyReceiveOrder(receiveOrder);
    }

    private void checkTime(String startTime){
        //此刻时间戳
        String nowTimestamp = DateUtil.getStringTimestamp(DateUtil.getNowDateTime());
        //当天11点时间戳
        String elevenTimestamp = DateUtil.getStringTimestamp(DateUtil.getNowDate() + appointmentTime);
        //出发时间戳
        String startTimestamp = DateUtil.getStringTimestamp(startTime);

        //出行时间小于当前时间，或者当前下单时间大于十一点后出行时间约今天，或者十一点后出行时间不大于今天
        if (startTimestamp.compareTo(nowTimestamp) <= 0 ||
                (elevenTimestamp.compareTo(nowTimestamp) <= 0 &&
                        startTimestamp.compareTo(DateUtil.getStringTimestamp(DateUtil.getTomorrow(new Date()) + " 00:00:00")) <= 0)) {
            throw new BizException(ApiResultCode.ERROR_START_TIME);
        }
    }

    private BigDecimal overBudget(BigDecimal distanceKm, BigDecimal freeDistance){
    //#计费规则 五公里内 按标准价格收取 超过五公里 按照每五公里加20元 不足五公里 按五公里算

        //总距离减去免费距离除以每五公里得出公里系数
        //返回一个BigDecimal数组，返回数组中包含两个元素，第一个元素为两数相除的商，第二个元素为余数。
        BigDecimal[] bigDecimals = distanceKm.subtract(freeDistance).divideAndRemainder(freeDistance);
        //如果余数>0.00 商加1
        if (bigDecimals[1].compareTo(new BigDecimal(0.00)) > 0){
            bigDecimals[0] = bigDecimals[0].add(new BigDecimal(1));//这是 不满5 公里按五公里算
        }
        // 超出金额
        BigDecimal overBudget = bigDecimals[0].multiply(unitPrice);
        return overBudget;
    }


    /**
     * 短信发送
     * @param phone 手机号码
     * @param smsTemplate
     * @param templateParam
     * @return
     */
    public ApiResult<Object> Send(String phone, String smsTemplate, Map<String,Object> templateParam){
        if (!BizEmpty(phone)){
            //发短信
            SmsParameterDto smsParameterDto =  new SmsParameterDto();
            smsParameterDto.setSmsTemplate(smsTemplate);
            smsParameterDto.setMobile(phone);
            smsParameterDto.setSignName("相伴医路");
            smsParameterDto.setTemplateParam(templateParam);
            ApiResult<Object> objectApiResult = messageFeign.sendSms(smsParameterDto);
            return objectApiResult;
        }
        return null;
    }
}